import classNames from 'classnames';
import React from 'react';

import { IDOMProps } from '../../utils/props';

export interface ICircleProgressProps {
  className?: string;
  style?: React.CSSProperties;
  /** 进度条百分比 */
  percent?: number;
  /** 进度条宽度 */
  strokeWidth?: number;
  /** 进度条颜色 */
  strokeColor?: string;
  /** 进度条轨迹填充色 */
  trailColor?: string;
  /** 进度条边缘形状, round:圆角 square：方角 */
  strokeLinecap?: 'round' | 'square';
  /** 获取文案内容函数 */
  format?: (percent: number) => (React.ReactNode | string);
  /** 是否显示进度数值 */
  showText?: boolean;
  /** 视窗宽度 */
  width?: number;
  /** 视窗高度 */
  height?: number;
  /** 开始角度 */
  startDegree?: number;
}

export interface ICircleProgressState {
  strokeWidth: number;
}

/** 环形最外层半径 */
const RADIUS = 50;
/** 进度条宽度的百分比默认值 */
const STROKE_WIDTH = 6;
/** 动画持续时间 */
const ANIMATE_DURATION = 200;
/** 动画延迟时间 */
const ANIMATE_DELAY = 20;

export class CircleProgress extends React.Component<ICircleProgressProps, ICircleProgressState> {
  public static defaultProps = {
    percent: 0,
    width: 100,
    height: 100,
    className: '',
    style: {},
    strokeWidth: STROKE_WIDTH,
    strokeColor: '#00b7fe',
    trailColor: '#fafafa',
    strokeLinecap: 'round',
    startDegree: 0,
    showText: true,
  };

  public strokeWidth: number;
  public timer: number | null;
  constructor(props: ICircleProgressProps) {
    super(props);
    this.state = {
      strokeWidth: !props.percent ? 0 : props.strokeWidth || STROKE_WIDTH,
    };
    this.strokeWidth = props.strokeWidth || STROKE_WIDTH;
    this.timer = null;
  }

  public componentDidUpdate(prevProps: ICircleProgressProps, prevState: ICircleProgressState) {
    if (this.props.percent !== prevProps.percent) {
      this.clearTimer();
      if (prevProps.percent === 0) {
        this.timer = window.setTimeout(() => {
          this.setState({
            strokeWidth: this.strokeWidth,
          });
        }, ANIMATE_DELAY);
      }
      if (this.props.percent === 0) {
        this.timer = window.setTimeout(() => {
          this.setState({
            strokeWidth: 0,
          });
        }, ANIMATE_DURATION + ANIMATE_DELAY);
      }
    }
  }

  public componentWillUnmount() {
    this.clearTimer();
  }

  public render() {
    const { width, height, className, style, trailColor, strokeLinecap, strokeColor,
      startDegree, showText, percent = 0, format, ...domProps } = this.props;
    const { strokeWidth } = this.state;
    const strokeCenterRadius = RADIUS - this.strokeWidth / 2;
    const drawPath = this.getDrawPath();
    const circumference = 2 * Math.PI * strokeCenterRadius;
    const strokeDasharray = `${circumference * percent / 100}px, ${circumference * 100}px`;
    return (
      <div
        {...domProps as IDOMProps}
        className={classNames('br-progress br-progress__circle', className)}
        style={{ width, height, ...style }}
      >
        <svg
          viewBox={`0 0 ${RADIUS * 2} ${RADIUS * 2}`}
          style={{ transform: `rotate(${startDegree}deg)` }}
        >
          <path
            d={drawPath}
            className="br-progress__circle-trail"
            fill="none"
            strokeWidth={this.strokeWidth}
            stroke={trailColor}
          />
          <path
            d={drawPath}
            className="br-progress__circle-path"
            stroke={strokeColor}
            fill="none"
            strokeWidth={strokeWidth}
            strokeLinecap={strokeLinecap}
            style={{
              strokeDasharray,
              transition: `stroke-dasharray ${ANIMATE_DURATION / 1000}s ease-in-out ${ANIMATE_DELAY / 1000}s`,
            }}
          />
        </svg>
        {
          showText &&
          <span className="br-progress__circle-text">{format ? format(percent) : `${percent}%`}</span>
        }
      </div>
    );
  }

  /**
   * 获取path画的环形路径
   */
  public getDrawPath() {
    const strokeCenterRadius = RADIUS - this.strokeWidth / 2;
    return `M ${RADIUS},${RADIUS}
    m 0, -${strokeCenterRadius}
    a ${strokeCenterRadius},${strokeCenterRadius} 0 1 1 0,${strokeCenterRadius * 2}
    a ${strokeCenterRadius},${strokeCenterRadius} 0 1 1 0,-${strokeCenterRadius * 2}`;
  }

  /**
   * 清除定时器
   */
  public clearTimer() {
    if (this.timer) {
      window.clearTimeout(this.timer);
      this.timer = null;
    }
  }
}
